package br.com.vexillum.view;

import java.lang.reflect.Field;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.select.annotation.Wire;
import org.zkoss.zul.Listbox;
import org.zkoss.zul.Messagebox;
import org.zkoss.zul.Window;
import org.zkoss.zul.impl.InputElement;

import br.com.vexillum.control.GenericControl;
import br.com.vexillum.control.manager.ExceptionManager;
import br.com.vexillum.model.CommonEntity;
import br.com.vexillum.util.ReflectionUtils;
import br.com.vexillum.util.Return;

public abstract class CRUDComposer<E extends CommonEntity, G extends GenericControl<E>> extends GenericComposer {

	private static final long serialVersionUID = 1L;

	protected E entity;

	@Wire
	private Window frmCrudBasico;

	@Wire
	protected Listbox resultPesquisa;
	
	protected List<E> listEntity;
	protected E selectedEntity;

	public E getEntity() {
		return entity;
	}

	public void setEntity(E entidade) {
		this.entity = entidade;
	}

	public List<E> getListEntity() {
		return listEntity;
	}

	public void setListEntity(List<E> listEntity) {
		this.listEntity = listEntity;
	}

	public E getSelectedEntity() {
		return selectedEntity;
	}

	public void setSelectedEntity(E selectedEntity) {
		this.selectedEntity = selectedEntity;
	}
	
	protected void initEntity(){
		setEntity(getEntityObject());
	}

	public void doAfterCompose(Component comp) throws Exception {
		super.doAfterCompose(comp);
		initEntity();
	}
	
	public Return saveEntity() {
		if(getEntity().getId() != null && getEntity().getId() != 0){
			return getControl().doAction("update");
		}
		return getControl().doAction("save");
	}

	@SuppressWarnings("unchecked")
	public Return searchEntitys() {
		Return ret = getControl().doAction("searchByCriteria");
		setListEntity((List<E>) ret.getList());
		binder.loadAll();
		return ret;
	}
	
	@SuppressWarnings("unchecked")
	public Return searchByHQL() {
		Return ret = getControl().doAction("searchByHQL");
		setListEntity((List<E>) ret.getList());
		binder.loadAll();
		return ret;
	}
	
	@SuppressWarnings("unchecked")
	public Return listAll(){
		Return ret = getControl().doAction("listAll");
		setListEntity((List<E>) ret.getList());
		binder.loadAll();
		return ret;
	}

	public Return deleteEntity() {
		binder.saveAll();
		setEntity(selectedEntity);
		return getControl().doAction("delete");
	}
	
	@SuppressWarnings({ "unchecked", "rawtypes" })
	protected void showDeleteConfirmation(String message){
		Messagebox.show(message, "Confirma��o", Messagebox.OK | Messagebox.CANCEL, Messagebox.QUESTION, new EventListener() {
		    public void onEvent(Event evt) throws InterruptedException {
		        if (evt.getName().equals("onOK")) {
		        	deleteUser();
		        } 
		    }
		});
	}
	
	private void deleteUser(){
		if(doAction("deleteEntity")){
    		getListEntity().remove(getSelectedEntity());
        	setSelectedEntity(null);
    	}
	}

	public void alterarEntidade() {
		binder.saveAll();
		setEntity(selectedEntity);
		showCrudForm();
	}

	public void novaEntidade() {
		showCrudForm();
	}
	
	public void disableComponentsNoUpdatables(Component comp){
		try {
			List<Field> comps = ReflectionUtils.getNonUpdatableFields(entity);
			for(Iterator<Field> i = comps.iterator(); i.hasNext();){
				Field f = i.next();
				Component campo = getComponentById(comp, "fld" + StringUtils.capitalize(f.getName()));
				if(campo != null){
					if(campo instanceof InputElement){
						((InputElement)campo).setDisabled(true);
					}
				}
			}
		} catch (Exception e) {
			new ExceptionManager(e).treatException();
		}
	}
	
	/**
	 * @return o controle espec�fico para cada composer
	 */
	public abstract G getControl();

	/**
	 * Dever� ser implementado o composer para retornar o objeto de dominio o
	 * qual ele corresponde.
	 * 
	 * @return classe que extends de CommonEntity
	 */
	public abstract E getEntityObject();

	/**
	 * @return o formul�rio para cadastrar e alterar uma entidade para que ela
	 *         retorne um formul�rio diferente basta sobrescrever este m�todo
	 */
	public Window getCrudFrm() {
		return frmCrudBasico;
	}

	public void showCrudForm() {
		getCrudFrm().setMode(Window.MODAL);
		getCrudFrm().setVisible(true);
		getCrudFrm().doModal();
	}

	public void hideCrudForm() {
		getCrudFrm().setVisible(false);
	}
	
}
